using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using TelnetExpect;
using System.IO;

namespace TelnetTests
{

    [TestFixture]
    public class TelnetStream_NegotiationPositive : TestsBase
    {
        //--------
        static void BothEchoEnabled(TelnetStream telnet)
        {
            telnet.SetLocalMode(TelnetOption.Echo, true);
            Assert.IsTrue(telnet.GetLocalMode(TelnetOption.Echo), "Remote Echo enabled");
        }

        static readonly TelnetOption[] NoOptionsEnabled = { };
        static readonly TelnetOption[] OptionsEnabled_Echo = { TelnetOption.Echo };
        static readonly TelnetOption[] OptionsEnabled_Echo_SuppGa = { TelnetOption.Echo, TelnetOption.SuppressGoAhead };

        [Test]
        public void Acceptable_Do()
        {
            byte[] input = { IAC, DO, OptionCode.Echo };
            DoTest(input, ExpectedInputNone, ExpectedResponsesEchoWill,
                BothEchoEnabled, OptionsEnabled_Echo, null);
        }

        [Test]
        public void Acceptable_Dont()
        {
            byte[] input = { IAC, DONT, OptionCode.Echo };
            DoTest(input, ExpectedInputNone, ExpectedResponsesNone,
                BothEchoEnabled, null, null);
        }

        [Test]
        public void Acceptable_Will()
        {
            byte[] input = { IAC, WILL, OptionCode.Echo };
            DoTest(input, ExpectedInputNone, ExpectedResponsesEchoDo,
                BothEchoEnabled, null, OptionsEnabled_Echo);
        }

        [Test]
        public void Acceptable_Wont()
        {
            byte[] input = { IAC, WONT, OptionCode.Echo };
            DoTest(input, ExpectedInputNone, ExpectedResponsesNone,
                BothEchoEnabled, null, null);
        }

        //--------
        [Test]
        public void Acceptable_Twice_Do()
        {
            byte[] input = { IAC, DO, OptionCode.Echo };
            DoTest(ArrayUtils_NTimes(input, 2), ExpectedInputNone, ExpectedResponsesEchoWill,
                BothEchoEnabled, OptionsEnabled_Echo, null);
        }

        [Test]
        public void Acceptable_Twice_Dont()
        {
            byte[] input = { IAC, DONT, OptionCode.Echo };
            DoTest(ArrayUtils_NTimes(input, 2), ExpectedInputNone, ExpectedResponsesNone,
                BothEchoEnabled, null, null);
        }

        [Test]
        public void Acceptable_Twice_Will()
        {
            byte[] input = { IAC, WILL, OptionCode.Echo };
            DoTest(ArrayUtils_NTimes(input, 2), ExpectedInputNone, ExpectedResponsesEchoDo,
                BothEchoEnabled, null, OptionsEnabled_Echo);
        }

        [Test]
        public void Acceptable_Twice_Wont()
        {
            byte[] input = { IAC, WONT, OptionCode.Echo };
            DoTest(ArrayUtils_NTimes(input, 2), ExpectedInputNone, ExpectedResponsesNone,
                BothEchoEnabled, null, null);
        }

        //--------
        [Test]
        public void Acceptable_TwiceDo_TwiceDont()
        {
            byte[] input = { 
                IAC, DO, OptionCode.Echo,
                IAC, DO, OptionCode.Echo,
                IAC, DONT, OptionCode.Echo,
                IAC, DONT, OptionCode.Echo,
            };
            DoTest(input, ExpectedInputNone, ExpectedResponsesEchoWillThenWont,
                BothEchoEnabled,
                null, null);
        }

        //--------
        //TODO [Test] public void WinXP()
        //{
        //    byte[] input = {
        //
        //    };
        //}


        [Test]
        public void Real__cvs_synchro_net()
        {
            /*
                C:\>TelnetConsole.exe  cvs.synchro.net

                Synchronet BBS for Linux  Version 3.15
                Connection from: 80.229.238.154
                Resolving hostname...
                Received command: IAC 'Will' 'Echo' (FF-FB-01)
                Responding 'Do' 'Echo' (0x01)
                Received command: IAC 'Will' 'SuppressGoAhead' (FF-FB-03)
                Responding 'Do' 'SuppressGoAhead' (0x03)
                Received command: IAC 'Do' 'TerminalType' (FF-FD-18)
                Responding 'Wont' 'TerminalType' (0x18)
                Received command: IAC 'Do' 'TerminalSpeed' (FF-FD-20)
                Responding 'Wont' 'TerminalSpeed' (0x20)
                Received command: IAC 'Do' 'SendLocation' (FF-FD-17)
                Responding 'Wont' 'SendLocation' (0x17)
                Received command: IAC 'Do' 'NegotiateAboutWindowSize' (FF-FD-1F)
                Responding 'Wont' 'NegotiateAboutWindowSize' (0x1F)
                Sending answers: [ FF-FD-01-FF-FD-03-FF-FC-18-FF-FC-20-FF-FC-17-FF-FC-1F ]

                      Synchronet BBS for Linux  Version 3.15  Copyright 2009 Rob Swindell
                Received command: IAC 'Dont' 'TerminalType' (FF-FE-18)
                Responding 'Wont' 'TerminalType' (0x18)
                Received command: IAC 'Dont' 'TerminalSpeed' (FF-FE-20)
                Responding 'Wont' 'TerminalSpeed' (0x20)
                Received command: IAC 'Dont' 'SendLocation' (FF-FE-17)
                Responding 'Wont' 'SendLocation' (0x17)
                Received command: IAC 'Dont' 'NegotiateAboutWindowSize' (FF-FE-1F)
                Responding 'Wont' 'NegotiateAboutWindowSize' (0x1F)
                Sending answers: [ FF-FC-18-FF-FC-20-FF-FC-17-FF-FC-1F ]
             */
            byte[] input = {
                0xFF, 0xFB, 0x01, //IAC 'Will' 'Echo' 
                0xFF, 0xFB, 0x03, //IAC 'Will' 'SuppressGoAhead' 
                //
                0xFF, 0xFD, 0x18, //IAC 'Do'   'TerminalType' 
                0xFF, 0xFD, 0x20, //IAC 'Do'   'TerminalSpeed' 
                0xFF, 0xFD, 0x17, //IAC 'Do'   'SendLocation' 
                0xFF, 0xFD, 0x1F, //IAC 'Do'   'NegotiateAboutWindowSize' 
                //
                0xFF, 0xFE, 0x18, //IAC 'Dont' 'TerminalType' 
                0xFF, 0xFE, 0x20, //IAC 'Dont' 'TerminalSpeed' 
                0xFF, 0xFE, 0x17, //IAC 'Dont' 'SendLocation' 
                0xFF, 0xFE, 0x1F, //IAC 'Dont' 'NegotiateAboutWindowSize' 
            };
            byte[] expectedResponses = {
                IAC, DO, OptionCode.Echo,
                IAC, DO, OptionCode.SuppressGoAhead,
                //
                IAC, WONT, OptionCode.TerminalType,
                IAC, WONT, OptionCode.TerminalSpeed,
                IAC, WONT, OptionCode.SendLocation,
                IAC, WONT, OptionCode.NegotiateAboutWindowSize,
                // We don't respond to the last four as they're just responses to 
                // our WONTs, and we should not respond when we're in that state 
                // already.
            };
            DoTest(input, ExpectedInputNone, expectedResponses,
                null, null, OptionsEnabled_Echo_SuppGa);
        }

    }
}
